﻿using System;
using System.Collections.Generic;

namespace SqueezeboxLib
{
    /// <summary>
    /// Represents a Squeezebox Playlist
    /// </summary>
    public class SqueezeboxPlaylist
    {
        public static class Commands
        {
            /// <summary>
            /// The "play" command allows to start playing the current playlist. 
            /// The "fadeInSecs" parameter may be passed to specify fade-in period.
            /// </summary>
            public const string Play = "play";
            public const string Stop = "stop";
            public const string Pause = "pause";
            public const string Time = "time";
            public const string PlaylistPlay = "playlist play";
            public const string PlaylistAdd = "playlist add";
            public const string PlaylistInsert = "playlist insert";
            public const string PlaylistDeleteItem = "playlist deleteitem";
            public const string PlaylistMove = "playlist move";
            public const string PlaylistDelte = "playlist delete";
            public const string PlaylistPreview = "playlist preview";
            public const string PlaylistResume = "playlist resume";
            public const string PlaylistSave = "playlist save";
            public const string PlaylistLoadAlbum = "playlist loadalbum";
            public const string PlaylistAddAlbum = "playlist addalbum";
            public const string PlaylistLoadTracks = "playlist loadtracks";
            public const string PlaylistAddTracks = "playlist addtracks";
            public const string PlaylistInsertAlbum = "playlist insertalbum";
            public const string PlaylistDeleteAlbum = "playlist deletealbum";
            public const string PlaylistClear = "playlist clear";
            public const string PlaylistZap = "playlist zap";
            public const string PlaylistShuffle = "playlist shuffle";
            public const string PlaylistRepeat = "playlist repeat";
            public const string PlaylistControl = "playlistcontrol";
        }

        public static class Queries
        {
            public const string Mode = "mode ?";
            public const string Genere = "genre ?";
            public const string Artist = "artist ?";
            public const string Album = "album ?";
            public const string Title = "title ?";
            public const string Duration = "duration ?";
            public const string Remote = "remote ?";
            public const string CurrentTitle = "current_title ?";
            public const string Path= "path ?";
            public const string PlaylistName = "playlist name ?";
            public const string PlaylistUrl = "playlist url ?";
            public const string PlaylistModified = "playlist modified ?";
            public const string PlaylistPlaylistInfo = "playlist playlistsinfo";
            public const string PlaylistIndex = "playlist index";
            public const string PlaylistGenere = "playlist genre ?";
            public const string PlaylistArtist = "playlist artist ?";
            public const string PlaylistAlbum = "playlist album ?";
            public const string PlaylistTitle = "playlist title ?";
            public const string PlaylistPath = "playlist path ?";
            public const string PlaylistRemote = "playlist remote ?";
            public const string PlaylistDuration = "playlist duration ?";
            public const string PlaylistTracks = "playlist tracks ?";
        }   

        public Action<string> Send;

        public SqueezeboxPlayer Player;

        public ShuffleState ShuffleState { get; private set; }

        public PlaylistMode Mode { get; private set; }

        /// <summary>
        /// Gets the PlayerID of the player the playlist belongs to.
        /// </summary>
        public string PlayerID { get; private set; }

        /// <summary>
        /// Occurs when the playlist receives a message
        /// </summary>
        public event PlaylistMessageReceivedEventHandler MessageReceived;

        /// <summary>
        /// Occurs at the start of a new song.
        /// </summary>
        public event EventHandler<PlaylistNewSongEventArgs> NewSongStarted;

        /// <summary>
        /// Occurs when the playlist mode change
        /// </summary>
        public event EventHandler<PlaylistModeChangedEventArgs> ModeChanged;

        /// <summary>
        /// Creates a new Squeezebox Playlist
        /// </summary>
        /// <param name="playerID">ID of the player the playlist belongs to</param>
        /// <param name="send">Send CLI message delegate</param>
        /// <param name="player">the player this playlist belongs to</param>
        public SqueezeboxPlaylist(string playerID, Action<string> send, SqueezeboxPlayer player)
        {
            PlayerID = playerID;
            Send = send;
            Player = player;
            Player.MessageReceived += SqueezeboxPlayerMessageReceived;
        }

        private void SqueezeboxPlayerMessageReceived(object sender, MessageReceivedEventArgs e)
        {
            string[] split = e.Message.Split(' ');

            if (split[1] == "playlist")
            {
                PlaylistCommand command = PlaylistCommand.unknown;

                Enum.TryParse(split[2], true, out command);

                string result = string.Empty;


                if(command != PlaylistCommand.unknown)
                {
                    result = e.Message.Split('?')[1];// everything after split[3] (which is '?')
                }
                else
                {
                    //00:26:82:c3:4e:5e playlist newsong Social Disability 7
                    if (NewSongStarted != null && split[2] == "newsong")
                    {
                        int trackNumber = int.Parse(split[split.Length - 1]);

                        string songTitle = "";

                        for (int i = 0; i < split.Length; i++)
                        {
                            if (i > 2 && i < split.Length - 1)
                            {
                                songTitle += split[i];
                            }
                        }

                        NewSongStarted(this, new PlaylistNewSongEventArgs(PlayerID, songTitle, trackNumber));
                    }

                    result = e.Message;
                }


                if (MessageReceived != null)
                {
                    MessageReceived(this, new PlaylistMessageReceivedEventArgs(PlayerID, command, result));
                }
            }
        }

        private void SendCommand(PlaylistCommand command, params object[] parameters)
        {
            string message = string.Format("{0} {1} {2} {3}", PlayerID, "playlist", command, string.Join(" ", parameters));
            Send(message);
        }

        private void SendQuery(PlaylistCommand query)
        {
            string message = string.Format("{0} {1} {2} ?", PlayerID, "playlist", query);
            Send(message);
        }

        /// <summary>
        /// puts the specified song URL, playlist or directory contents into the current playlist and plays starting at the first item. Any songs previously in the playlist are discarded.
        /// </summary>
        /// <param name="item">Song URL, playlist or directory</param>
        /// <param name="title">Optional title (This can be useful for remote URLs)</param>
        /// <param name="fadeInSecs">Optional fade-in period</param>
        public void Play(string item, string title = "", double fadeInSecs = 0)
        {
            SendCommand(PlaylistCommand.play, title, fadeInSecs > 0 ? fadeInSecs.ToString() : "");
        }

        public void Add(string item)
        {
            SendCommand(PlaylistCommand.add, item);
        }

        public void Insert(string item)
        {
            SendCommand(PlaylistCommand.insert, item);
        }

        public void DeleteItem(string item)
        {
            SendCommand(PlaylistCommand.deleteitem, item);
        }

        public void Move(string item, int fromIndex, int toIndex)
        {
            SendCommand(PlaylistCommand.move, item, fromIndex, toIndex);
        }

        public void Delete(int songIndex)
        {
            SendCommand(PlaylistCommand.delete, songIndex);
        }

        public void Preview(List<TaggedParameter> taggedParameters)
        {
            SendCommand(PlaylistCommand.preview, string.Join(" ", taggedParameters));
        }

        public void Resume(string playlist, List<TaggedParameter> taggedParameters)
        {
            SendCommand(PlaylistCommand.resume, string.Join(" ", taggedParameters));
        }

        public void Save(string fileName, List<TaggedParameter> taggedParameters)
        {
            SendCommand(PlaylistCommand.save, fileName, string.Join(" ", taggedParameters));
        }

        public void LoadAlbum(string genere, string artist, string album)
        {
            SendCommand(PlaylistCommand.loadalbum, genere, artist, album);
        }

        public void AddAlbum(string genere, string artist, string album)
        {
            SendCommand(PlaylistCommand.addalbum, genere, artist, album);
        }

        public void LoadTracks(string searchParam)
        {
            SendCommand(PlaylistCommand.loadtracks, searchParam);
        }

        public void AddTracks(string searchParam)
        {
            SendCommand(PlaylistCommand.addtracks, searchParam);
        }

        public void InsertAlbum(string genere, string artist, string album)
        {
            SendCommand(PlaylistCommand.insertalbum, genere, artist, album);
        }

        public void DeleteAlbum(string genere, string artist, string album)
        {
            SendCommand(PlaylistCommand.deletealbum, genere, artist, album);
        }

        public void Clear()
        {
            SendCommand(PlaylistCommand.clear);
        }

        public void Zap(int songIndex)
        {
            SendCommand(PlaylistCommand.zap, songIndex);
        }

        public void Name()
        {
            SendQuery(PlaylistCommand.name);
        }

        public void RequestURL()
        {
            SendQuery(PlaylistCommand.url);
        }

        public void RequestModified()
        {
            SendQuery(PlaylistCommand.modified);
        }

        public void RequestPlaylistInfo(List<TaggedParameter> taggedParameters)
        {
            SendCommand(PlaylistCommand.playlistinfo, string.Join(" ", taggedParameters));
        }

        public void RequestIndex(string indexValue, double fadeInDuration = 0)
        {
            SendCommand(PlaylistCommand.index, indexValue, fadeInDuration);
        }

        public void RequestGenere()
        {
            SendQuery(PlaylistCommand.genere);
        }

        public void RequestArtist()
        {
            SendQuery(PlaylistCommand.artist);
        }

        public void RequestAlbum()
        {
            SendQuery(PlaylistCommand.album);
        }

        public void RequestTitle()
        {
            SendQuery(PlaylistCommand.title);
        }

        public void RequestPath()
        {
            SendQuery(PlaylistCommand.path);
        }

        public void RequestRemote()
        {
            SendQuery(PlaylistCommand.remote);
        }

        public void RequestDuration()
        {
            SendQuery(PlaylistCommand.duration);
        }

        public void RequestTracks()
        {
            SendQuery(PlaylistCommand.tracks);
        }

        public void Shuffle(ShuffleState shuffleState)
        {
            SendCommand(PlaylistCommand.shuffle, (int)shuffleState);
        }

        public void Repeat(RepeatState repeatState)
        {
            SendCommand(PlaylistCommand.repeat, (int)repeatState);
        }

        /// <summary>
        /// Enables playlist operations using IDs as returned by extended CLI queries (titles, artists, playlists, etc).
        /// </summary>
        /// <param name="taggedParameters"></param>
        public void PlaylistControl(List<TaggedParameter> taggedParameters)
        {
            SendCommand(PlaylistCommand.playlistcontrol, string.Join(" ", taggedParameters));
        }
    }
}
